package com.example.consumptionrecords.config.shiro;

import com.example.consumptionrecords.entity.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.SerializeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * RedisSessionDAO shiro sessionDao层的实现 通过redis
 * 孙敬佳
 * 2024 \ 03 \ 03
 */

@Slf4j
public class RedisSessionDAO extends AbstractSessionDAO {

		private static Logger logger = LoggerFactory.getLogger(org.crazycake.shiro.RedisSessionDAO.class);
		/**
		 * shiro-redis的session对象前缀
		 */
		private RedisManager redisManager;

		/**
		 * The Redis key prefix for the sessions
		 */
		private String keyPrefix = "shiro_redis_session:";

		@Override
		public void update(Session session) throws UnknownSessionException {
			this.saveSession(session);
		}

		/**
		 * save session
		 * @param session
		 * @throws UnknownSessionException
		 */
		private void saveSession(Session session) throws UnknownSessionException{
			if(session == null || session.getId() == null){
				logger.error("session or session id is null");
				return;
			}

			byte[] key = getByteKey(session.getId());
			byte[] value = SerializeUtils.serialize(session);

			final User[] user = {null};
			session.getAttributeKeys().forEach(item -> {
				Object attribute = session.getAttribute(item);
				if (attribute instanceof SimplePrincipalCollection simplePrincipalCollection) {
					Object primaryPrincipal = simplePrincipalCollection.getPrimaryPrincipal();
					if (primaryPrincipal != null) {
						user[0] = (User) primaryPrincipal;
					}
				}
			});
			if (user[0] == null) {
				session.setTimeout(3000);
				this.redisManager.set(key, value, 3);
			} else {
				session.setTimeout(redisManager.getExpire() * 1000L);
				this.redisManager.set(key, value, redisManager.getExpire());
			}
		}

		@Override
		public void delete(Session session) {
			if(session == null || session.getId() == null){
				logger.error("session or session id is null");
				return;
			}
			redisManager.del(this.getByteKey(session.getId()));

		}

		@Override
		public Collection<Session> getActiveSessions() {
			Set<Session> sessions = new HashSet<Session>();

			Set<byte[]> keys = redisManager.keys(this.keyPrefix + "*");
			if(keys != null && keys.size()>0){
				for(byte[] key:keys){
					Session s = (Session)SerializeUtils.deserialize(redisManager.get(key));
					sessions.add(s);
				}
			}

			return sessions;
		}

		@Override
		protected Serializable doCreate(Session session) {
			Serializable sessionId = this.generateSessionId(session);
			this.assignSessionId(session, sessionId);
			this.saveSession(session);
			return sessionId;
		}

		@Override
		protected Session doReadSession(Serializable sessionId) {
			if(sessionId == null){
				logger.error("session id is null");
				return null;
			}

			Session s = (Session)SerializeUtils.deserialize(redisManager.get(this.getByteKey(sessionId)));
			return s;
		}

		/**
		 * 获得byte[]型的key
		 * @return
		 */
		private byte[] getByteKey(Serializable sessionId){
			String preKey = this.keyPrefix + sessionId;
			return preKey.getBytes();
		}

		public RedisManager getRedisManager() {
			return redisManager;
		}

		public void setRedisManager(RedisManager redisManager) {
			this.redisManager = redisManager;

			/**
			 * 初始化redisManager
			 */
			this.redisManager.init();
		}

		/**
		 * Returns the Redis session keys
		 * prefix.
		 * @return The prefix
		 */
		public String getKeyPrefix() {
			return keyPrefix;
		}

		/**
		 * Sets the Redis sessions key
		 * prefix.
		 * @param keyPrefix The prefix
		 */
		public void setKeyPrefix(String keyPrefix) {
			this.keyPrefix = keyPrefix;
		}
}
